/**
 * Places view uses a carousel widget to show lists of categories and a list of places.
 * The main categories are shown first. After choosing a category user can navigate 
 * deeper into subcategories or show places in the selected category or subcategory. 
 */

(function() {
	var view = View("places-view");
	
	qype.views.placesView = view;

	var categoryCarousel;
	var carouselStack = [];

	var links;
	
	var location = "";
	
	view.getHtml = function() {
		return sprintf('<div id="%s"><h1 class="title">&nbsp;</h1></div>', view.getId());
	};

	view.init = function() {
		this.initBack();
		categoryCarousel = CarouselWidget();
		this.getContainer().append(categoryCarousel.getHtml());
		resetCarouselItems(1);
	};
	
	view.setLocation = function(loc, title) {
		location = loc;
		this.getContainer().children('.title').text(title);
	};

	function backId(index) {
		return view.getId() + "-back-" + index;
	}

	function resetCarouselItems(index) {
		categoryCarousel.removeViews(index);
		var size = categoryCarousel.size();
		for(var i = 0; i <= index; i++) {
			if (!carouselStack[i]) {
				carouselStack[i] = CarouselItem(i);
			}
			if(i >= size) {
				categoryCarousel.addView(carouselStack[i].getHtml());
				carouselStack[i].toggleLoading(true);
				if(index > 0) {
					carouselStack[i].setBackLink(categoryCarousel.linkMwl(i - 1) + categoryCarousel.hideViewMwl(i) + carouselStack[i].loadingMwl());
				}
			}
		}
	}

	view.setLinks = function(l) {
		links = l;
		carouselStack[0].setBackLink(l.backToLocation);
	};
	
	function CarouselItem(index) {
		var id = 'places-stack-item-'+index;
		var that = Widget({id: id});
		
		that.loading = LoadingWidget({id: id+"-loading", label: qype.strings.loading});
		that.header = ElementWidget({id: id+"-header", tag: "h2"});
		that.list = ListWidget({id: id+"-list", emptyContent: sprintf('<div class="no-results">%s</div>', qype.strings.noResults)});
		
		that.getHtml = function() {
			var html = [
				this.loading.getHtml(),
				this.header.getHtml(),
				this.list.getHtml()
			];
			return html.join("");
		}
		
		that.setBackLink = function(onclickMwl) {
			view.addBack(backId(index), onclickMwl + (index > 0 ? view.showBackMwl(backId(index - 1)) : ""));
		}
		
		that.toggleLoading = function(display) {
			this.loading.toggle(display);
			this.header.toggle(!display);
			this.list.toggle(!display);
		}
		
		that.loadingMwl = function() {
			return this.loading.showLoadingMwl() + this.loading.showMwl() + this.header.hideMwl() + this.list.hideMwl();
		}
		
		that.showError = function(category, title, carouselIndex, isPlaces, status) {
			this.list.populate([]);
			this.loading.setError(util.networkErrorMessage(status, this.loading.showLoadingMwl() + (isPlaces ? loadPlacesMwl(category, title, carouselIndex) : loadCategoriesMwl(category, title, carouselIndex))));
			this.loading.showError();
			this.toggleLoading(true);
		}
		
		return that;
	}

	function categoriesToListItems(entries, onclickTemplate, category, title, carouselIndex) {
		function getLink(entry, relRegExp) {
			for(var i = 0; i < entry.links.length; i++) {
				if((entry.links[i].rel || "").match(relRegExp)) return entry.links[i].href;
			}
			return "";
		}
		
		function getId(entry) {
			return getLink(entry, /^self$/).split('/').pop();
		}
		
		function hasChildren(entry) {
			return !!getLink(entry, /children$/);
		}
		
		function getScript(entry) {
			if(hasChildren(entry)) {
				return loadCategoriesMwl(getId(entry), entry.full_title.value, carouselIndex);
			}
			return loadPlacesMwl(getId(entry), entry.full_title.value, carouselIndex) 
		}
		
		var results = $.map(entries, function(item, index) {
			return {
				onclick: sprintf(onclickTemplate, getScript(item.category)),
				name: item.category.full_title.value
			};
		});
		results.sort(function(a, b) {
			return (a.name > b.name) - (a.name < b.name);
		});
		if(carouselIndex > 1) {
			results.unshift({
				onclick: sprintf(onclickTemplate, loadPlacesMwl(category, title, carouselIndex)),
				name: qype.strings.showAll
			});
		}
		return results;
	}

	function loadCategoriesMwl(category, title, carouselIndex) {
		return sprintf("qype.views.placesView.loadCategories.call(qype.views.placesView,'%s','%s',%s);", category || '', title || '', carouselIndex || '');
	}

	view.loadCategories = function(category, title, carouselIndex) {
		carouselIndex = carouselIndex || 0;
		qype.API.get('place_categories', {
	        onSuccess: function(response) {
				resetCarouselItems(carouselIndex + 1);
				carouselStack[carouselIndex].header.html(carouselIndex ? sprintf(qype.strings.subcategory, title) : qype.strings.category);
				var onclickTemplate = [
					view.showBackMwl(backId(carouselIndex + 1)),
					categoryCarousel.linkMwl(carouselIndex + 1),
					categoryCarousel.hideViewMwl(carouselIndex),
					"%s"
				];
				var results = categoriesToListItems(response.results, onclickTemplate.join(""), category, title, carouselIndex + 1);
				carouselStack[carouselIndex].list.populate(results);
				carouselStack[carouselIndex].toggleLoading(false);
	        },
	        onFailure: function(response, status) {
				carouselStack[carouselIndex].showError(category, title, carouselIndex, false, status);
	        }
		}, category ? category + "/children" : undefined);
	};
	
	var placesCache;
	
	function placesToListItems(entries, onclickTemplate) {
		placesCache = entries;
		var results = $.map(entries, function(item, index) {
			return {
				onclick: sprintf(onclickTemplate, index),
				name: item.place.title
			};
		});
		return results;
	};
	
	function loadPlacesMwl(category, title, carouselIndex) {
		return sprintf("qype.views.placesView.loadPlaces.call(qype.views.placesView,'%s','%s',%s);", category || '', title || '', carouselIndex || '');
	}

	view.loadPlaces = function(category, title, carouselIndex) {
		qype.API.get('locators', {
	        onSuccess: function(response) {
				carouselStack[carouselIndex].header.html(title);
				var onclickTemplate = [
					links.place,
					"qype.views.placesView.loadPlace.call(qype.views.placesView, '%s');"
				];
				carouselStack[carouselIndex].list.populate(placesToListItems(response.results, onclickTemplate.join("")));
				carouselStack[carouselIndex].toggleLoading(false);
	        },
	        onFailure: function(response, status) {
				carouselStack[carouselIndex].showError(category, title, carouselIndex, true, status);
	        }
		}, location + "/places", {
			in_category: category,
			order: "rating"
		});
	};
	
	view.loadPlace = function(index) {
		qype.views.placeView.loadPlace(placesCache[index].place);
	}

	view.reset = function() {
		this.showBack(backId(0));
	};

	view.resetMwl = function() {
		return categoryCarousel.linkMwl("0", true) + carouselStack[1].loadingMwl() + this.showBackMwl(backId(0)); 
	};
})();
